/**
 * An apex class that keeps updates of a portal user in sync with its corresponding contact.
   Guest users are never able to access this page.
 */

public with sharing class MyProfilePageController{


    // variables
    private User user;
    private Person__c person;
    private boolean isEdit = false;
    private static final integer cooldown = 1; // cooldown time between tutor applications, in days
    
    public List<SelectOption> availableCourses {get; set;}
    public List<SelectOption> enrolledCourses {get; set;}
    public String[] availableSelected {get; set;}
    public String[] enrolledSelected {get; set;}
    

    public MyProfilePageController() {
        user = queryUser();
        person = queryPerson(user.UTORid__c);
        
        // guest users should never be able to access this page
        if (user.usertype == 'GUEST') {
            throw new NoAccessException();
        }
        
        //course picklist
        availableCourses = new List<SelectOption>();
        enrolledCourses = new List<SelectOption>();
        List<Course__c> courseList = [Select Name, Id FROM Course__c];
        Map<String, String> userCourses = getCourses(user.Courses__c);
        
        for (Integer i = 0; i < courseList.size(); i++){
            SelectOption course = new SelectOption(courseList[i].Id, courseList[i].Name);
            if (userCourses.containsKey(courseList[i].Name)){
                enrolledCourses.add(course);
            } else {
                availableCourses.add(course);
            }
        }
        SelectOptionSorter.doSort(availableCourses, SelectOptionSorter.FieldToSort.Label);
        SelectOptionSorter.doSort(enrolledCourses, SelectOptionSorter.FieldToSort.Label);
    }
    
    public User getUser() {
        return user;
    }
    
    public Boolean getIsEdit() {
        return isEdit;
    }
    
    public void edit() {
        isEdit=true;
    }
    
    public User queryUser(){
        return [SELECT id, email, usertype, firstname, lastname, phone, Student_Number__c, UTORid__c, isTutor__c, Last_Sent__c,
                street, city, country, postalcode, state, mobilephone, fax, Courses__c, contact.email
                FROM User
                WHERE id = :UserInfo.getUserId()];
    }
    
    public Person__c queryPerson(String UTORid){
        return [SELECT Id, Name, Email__c, City__c, Country__c, Courses__c, First_Name__c, Full_Name__c, Is_Tutor__c, 
                Last_Name__c, Postal_Zip_Code__c, Primary_Contact_Number__c, Province_State__c, Secondary_Contact_Number__c, 
                Street__c, Student_Number__c
                FROM Person__c
                WHERE Name =: UTORid];
    }

    public String getObjectUrl(String label, String id){
        return '<a href="https://tutorme-developer-edition.na12.force.com/' + id + '" target="_blank">' + label + '</a>';
    }
    
    public String getObjectId(String url){
        String domain = 'https://tutorme-developer-edition.na12.force.com/';
        return url.substring(url.indexOf(domain) + domain.length());
    }
    
    public Map<String, String> getCourses(String source){
        Map<String, String> courses = new Map<String, String>();
        if (source != null){
            String[] sourceCourses = source.split('<br>');
            for (Integer i = 0; i < sourceCourses.size(); i++){
                if (sourceCourses[i].length() > 4) {
                    String label = sourceCourses[i].substring(sourceCourses[i].indexOf('>') + 1, sourceCourses[i].indexOf('</a>', sourceCourses[i].indexOf('>') - 4 ));
                    String html = sourceCourses[i].substring(sourceCourses[i].indexOf('href="') + 6, sourceCourses[i].indexOf('"', sourceCourses[i].indexOf('href="') + 6));
                    courses.put(label, html);
                }
            }
        }
        return courses;
    }
    
    public String getCourseDetail() {
        SelectOptionSorter.doSort(availableCourses , SelectOptionSorter.FieldToSort.Label);
        SelectOptionSorter.doSort(enrolledCourses, SelectOptionSorter.FieldToSort.Label);
        String courseDetail = '';
        for (SelectOption option : enrolledCourses){
            courseDetail += getObjectUrl(option.getLabel(), option.getValue()) + '<br>';
        }
        return courseDetail;
    }
    
    public Integer getOptionIndex(List<SelectOption> options, String value){
        for (Integer i = 0; i < options.size(); i++){
            if (options[i].getValue().equals(value)){
                return i;
            }
        }
        return -1;
    }
    
    // save updates
    public void save() {
    
        if (user.contact != null) {    
            try {
                setContactFields(user.contact, user);
                update user.contact;
            } catch(Exception e) {
                ApexPages.addMessages(e);
            }          
        }
        
        
        user.Courses__c = getCourseDetail();
        enroll();
        
        try {
            update user;
            
        }catch(Exception e) {
            ApexPages.addMessages(e);
        }
        
        if (person != null){
            try {
                setPersonFields(person, user);
                update person;
            } catch(Exception e) {
                ApexPages.addMessages(e);
            }
        }
        isEdit=false;
    }
    
    public void enroll(){
        List<Enrollee__c> enrollees = new List<Enrollee__c>();
        enrollees = [Select Id, Course__c, Person__c FROM Enrollee__c
                    WHERE Person__c =: person.Id];
        Map<String, String> courses = getCourses(user.Courses__c);
        if (enrollees != null){
            delete enrollees;
        }
        if (courses != null){
            for (String label : courses.keySet()){
                Enrollee__c enrollee = new Enrollee__c(
                    Course__c = getObjectId(courses.get(label)),
                    Person__c = person.Id);
                try {
                   insert enrollee;
                } catch (DmlException e) {
                // Process exception here 
                }
            }
        }
    }
    
    // update contacts
    private static void setContactFields(Contact c, User u) {
        c.firstname = u.firstname;
        c.lastname = u.lastname;
        c.phone = u.phone;
        c.mobilephone = u.mobilephone;
        c.mailingstreet = u.street;
        c.mailingcity = u.city;
        c.mailingstate = u.state;
        c.mailingpostalcode = u.postalcode;
        c.mailingcountry = u.country;
    }
    
    private static void setPersonFields(Person__c p, User u){
        p.full_name__c = u.firstName + ' ' + u.lastName;
        p.email__c = u.email;
        p.is_Tutor__c = u.isTutor__c;
        p.Student_Number__c = u.Student_Number__c;
        p.First_Name__c = u.FirstName;
        p.Last_Name__c = u.LastName; 
        p.Street__c = u.Street;
        p.City__c = u.city;
        p.Province_State__c = u.state;
        p.Postal_Zip_Code__c = u.postalcode;
        p.Country__c = u.country;
        p.Primary_Contact_Number__c = u.phone;
        p.Secondary_Contact_Number__c = u.mobilePhone;
        p.Courses__c = u.Courses__c;
    }
    
    // cancel updates
    public void cancel() {
        isEdit=false;
        /*user = [SELECT id, email, usertype, firstname, lastname, phone, Student_Number__c, UTORid__c, isTutor__c, Last_Sent__c,
                street, city, country, postalcode, state, mobilephone, contact.email, Courses__c
                FROM User
                WHERE id = :UserInfo.getUserId()];*/
    }
    
    // change password
    public PageReference changePassword() {
        return Page.ChangePassword;
    }
    
    // apply for tutor position. Can only send an application once every interval
    public PageReference apply() {
       if (user.Last_Sent__c == null || user.Last_Sent__c.addDays(cooldown) < datetime.now()) {
           user.Last_Sent__c = datetime.now();
           update user;
           
           //Create tutor application
           Tutor_Application__c a = new Tutor_Application__c(Name=user.utorId__c);
           insert a;
           // Inform users that application was sent
           ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.CONFIRM, 'Your application has been sent to the administrator.');
           ApexPages.addMessage(msg);
           
           //Send Email
           sendEmail(user);
       }
       else {
            ApexPages.Message msg = new ApexPages.Message(ApexPages.Severity.Error, 'Sorry, you can only apply once every 24 hours');
            ApexPages.addMessage(msg);
       }
       return null;
    }
    
    //course picklist add button
    public PageReference add() {
        for (Integer i = 0; i < availableSelected.size(); i++) {
            Integer option = getOptionIndex(availableCourses, availableSelected[i]);
            enrolledCourses.add(availableCourses[option]);
            availableCourses.remove(option);
        }
        return null;
    }
    
    //course picklist remove button
    public PageReference remove() {
        for (Integer i = 0; i < enrolledSelected.size(); i++) {
            Integer option = getOptionIndex(enrolledCourses, enrolledSelected[i]);
            availableCourses.add(enrolledCourses[option]);
            enrolledCourses.remove(option);
        }
        return null;
    }
    
    // send email to Admin if user wants to sign up as Tutor
    public static void sendEmail(User u) {
    
        Tutor_Application__c t = [select id, name from Tutor_application__c where Name =: u.utorId__c][0];
        Messaging.reserveSingleEmailCapacity(2);
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {'c40teamd@gmail.com'};
        mail.setToAddresses(toAddresses);
        mail.setSenderDisplayName(u.firstname + ' ' + u.lastname);
        mail.setSubject('Tutor Sign Up');
        mail.setHtmlBody('Hi TutorMe Admin,<br/><br/>I am interested in becoming a tutor.<br/>'
        + 'Please approve my application for username <b>' + u.UTORid__c + '</b>.<br/><br/>'
        + 'Thanks,<br/>' + u.firstname + ' ' + u.lastname +'<br/><br/>' + 'You can view the application ' +
        '<a href="https://tutorme-developer-edition.na12.force.com/' + t.id + '">here</a>');
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});
    }

/***************Test methods***********************************************************************************/

    @IsTest(SeeAllData=true) static void testSave() {         
        // Modify the test to query for a portal user that exists in your org
        List<User> existingPortalUsers = [SELECT id, profileId, userRoleId FROM User WHERE UserRoleId <> null AND UserType='CustomerSuccess'];

        if (existingPortalUsers.isEmpty()) {
            User currentUser = [select id, title, firstname, lastname, email, phone, mobilephone, street, city, state, postalcode, country, isTutor__c
                                FROM User WHERE id =: UserInfo.getUserId()];
            MyProfilePageController controller = new MyProfilePageController();
            System.assertEquals(currentUser.Id, controller.getUser().Id, 'Did not successfully load the current user');
            System.assert(controller.isEdit == false, 'isEdit should default to false');
            controller.edit();
            System.assert(controller.isEdit == true);
            controller.cancel();
            System.assert(controller.isEdit == false);
            
            Contact c = new Contact();
            c.LastName = 'TestContact';
            insert c;
            
            setContactFields(c, currentUser);
            controller.save();
            System.assert(Page.ChangePassword.getUrl().equals(controller.changePassword().getUrl()));
        } else {
            User existingPortalUser = existingPortalUsers[0];
            String randFax = Math.rint(Math.random() * 1000) + '5551234';
            
            System.runAs(existingPortalUser) {
                MyProfilePageController controller = new MyProfilePageController();
                System.assertEquals(existingPortalUser.Id, controller.getUser().Id, 'Did not successfully load the current user');
                System.assert(controller.isEdit == false, 'isEdit should default to false');
                controller.edit();
                System.assert(controller.isEdit == true);
                
                controller.cancel();
                System.assert(controller.isEdit == false);
                
                controller.getUser().Fax = randFax;
                controller.save();
                System.assert(controller.isEdit == false);
            }
            
            // verify that the user and contact were updated
            existingPortalUser = [Select id, Contact.Fax from User where id =: existingPortalUser.Id];
            System.assert(existingPortalUser.fax == randFax);
            System.assert(existingPortalUser.Contact.fax == randFax);
        }
    }

}